<!--
  Copyright (c) 2006-2013, JGraph Ltd
  
  Schema example for mxGraph. This example demonstrates implementing
  a SQL schema editor.
-->
<html>
<head>
<title>Schema example</title>
<meta charset="utf-8">
<!-- Sets the basepath for the library if not in same directory -->
<script type="text/javascript">
    mxBasePath = '../src';
</script>

<!-- Loads and initializes the library -->
<script type="text/javascript" src="src/js/mxClient.js"></script>

<!-- Example code -->
<script type="text/javascript">
// Program starts here. Creates a sample graph in the
// DOM node with the specified ID. This function is invoked
// from the onLoad event handler of the document (see below).
function main(container, outline, toolbar, sidebar, status)
{
    // Checks if the browser is supported
    if (!mxClient.isBrowserSupported())
    {
        // Displays an error message if the browser is not supported.
        mxUtils.error('Browser is not supported!', 200, false);
    }
    else
    {
        // Specifies shadow opacity, color and offset
        mxConstants.SHADOW_OPACITY = 0.5;
        mxConstants.SHADOWCOLOR = '#C0C0C0';
        mxConstants.SHADOW_OFFSET_X = 5;
        mxConstants.SHADOW_OFFSET_Y = 6;

        // Table icon dimensions and position
        mxSwimlane.prototype.imageSize = 20;
        mxSwimlane.prototype.imageDx = 16;
        mxSwimlane.prototype.imageDy = 4;

        mxCellRenderer.prototype.imageDx = 180;

        // Changes swimlane icon bounds
        mxSwimlane.prototype.getImageBounds = function(x, y, w, h)
        {
            return new mxRectangle(x + this.imageDx, y + this.imageDy, this.imageSize, this.imageSize);
        };

        mxCellRenderer.prototype.getControlBounds = function(state, w, h)
        {
            if (state.control != null)
            {
                var s = state.view.scale;
                var cx = state.getCenterX();
                var cy = state.getCenterY();

                if (!state.view.graph.getModel().isEdge(state.cell))
                {
                    cx = state.x + w * s;
                    cy = state.y + h * s;

                    if (state.shape != null)
                    {
                        // TODO: Factor out common code
                        var rot = state.shape.getShapeRotation();

                        if (this.legacyControlPosition)
                        {
                            rot = mxUtils.getValue(state.style, mxConstants.STYLE_ROTATION, 0);
                        }
                        else
                        {
                            if (state.shape.isPaintBoundsInverted())
                            {
                                var t = (state.width - state.height) / 2;
                                cx += t;
                                cy -= t;
                            }
                        }

                        if (rot != 0)
                        {
                            var rad = mxUtils.toRadians(rot);
                            var cos = Math.cos(rad);
                            var sin = Math.sin(rad);

                            var point = mxUtils.getRotatedPoint(new mxPoint(cx, cy), cos, sin,
                                    new mxPoint(state.getCenterX(), state.getCenterY()));
                            cx = point.x;
                            cy = point.y;
                        }
                    }
                }

                return (state.view.graph.getModel().isEdge(state.cell)) ?
                        new mxRectangle(Math.round(cx - w / 2 * s), Math.round(cy - h / 2 * s), Math.round(w * s), Math.round(h * s))
                        : new mxRectangle(Math.round(cx - w / 2 * s)+state.width-20, Math.round(cy - h / 2 * s), Math.round(w * s), Math.round(h * s));
            }

            return null;
        };

        // Defines an icon for creating new connections in the connection handler.
        // This will automatically disable the highlighting of the source vertex.
        mxConnectionHandler.prototype.connectImage = new mxImage('images/connector.gif', 16, 16);

        // Prefetches all images that appear in colums
        // to avoid problems with the auto-layout
        var keyImage = new Image();
        keyImage.src = "images/key.png";

        var plusImage = new Image();
        plusImage.src = "images/plus.png";

        var checkImage = new Image();
        checkImage.src = "images/check.png";

        // Workaround for Internet Explorer ignoring certain CSS directives
        if (mxClient.IS_QUIRKS)
        {
            document.body.style.overflow = 'hidden';
            new mxDivResizer(container);
            new mxDivResizer(outline);
            new mxDivResizer(toolbar);
            new mxDivResizer(sidebar);
            new mxDivResizer(status);
        }

        // Creates the graph inside the given container. The
        // editor is used to create certain functionality for the
        // graph, such as the rubberband selection, but most parts
        // of the UI are custom in this example.
        var editor = new mxEditor();
        var graph = editor.graph;
        var model = graph.model;

        // Disables some global features
        graph.setConnectable(true);
        graph.setCellsDisconnectable(false);
        graph.setCellsCloneable(false);
        graph.swimlaneNesting = false;
        graph.dropEnabled = true;

        // Does not allow dangling edges
        graph.setAllowDanglingEdges(false);

        // Forces use of default edge in mxConnectionHandler
        graph.connectionHandler.factoryMethod = null;

        // Only tables are resizable
        graph.isCellResizable = function(cell)
        {
            return this.isSwimlane(cell);
        };

        // Only tables are movable
        graph.isCellMovable = function(cell)
        {
            return this.isSwimlane(cell);
        };

        // Sets the graph container and configures the editor
        editor.setGraphContainer(container);
        var config = mxUtils.load(
                'editors/config/keyhandler-minimal.xml').
                getDocumentElement();
        editor.configure(config);

        // Configures the automatic layout for the table columns
        editor.layoutSwimlanes = true;
        editor.createSwimlaneLayout = function ()
        {
            var layout = new mxStackLayout(this.graph, false);
            layout.fill = true;
            layout.resizeParent = true;

            // Overrides the function to always return true
            layout.isVertexMovable = function(cell)
            {
                return true;
            };

            return layout;
        };

        // Text label changes will go into the name field of the user object
        graph.model.valueForCellChanged = function(cell, value)
        {
            if (value.name != null)
            {
                return mxGraphModel.prototype.valueForCellChanged.apply(this, arguments);
            }
            else
            {
                var old = cell.value.name;
                cell.value.name = value;
                return old;
            }
        };

        // Columns are dynamically created HTML labels
        graph.isHtmlLabel = function(cell)
        {
            return !this.isSwimlane(cell) &&
                    !this.model.isEdge(cell);
        };

        // Edges are not editable
        graph.isCellEditable = function(cell)
        {
            return !this.model.isEdge(cell);
        };

        // Returns the name field of the user object for the label
        graph.convertValueToString = function(cell)
        {
            if (cell.value != null && cell.value.name != null)
            {
                return cell.value.name;
            }

            return mxGraph.prototype.convertValueToString.apply(this, arguments); // "supercall"
        };

        // Returns the type as the tooltip for column cells
        graph.getTooltip = function(state)
        {
            if (this.isHtmlLabel(state.cell))
            {
                return 'Type: '+state.cell.value.type;
            }
            else if (this.model.isEdge(state.cell))
            {
                var source = this.model.getTerminal(state.cell, true);
                var parent = this.model.getParent(source);

                return parent.value.name+'.'+source.value.name;
            }

            return mxGraph.prototype.getTooltip.apply(this, arguments); // "supercall"
        };

        // Creates a dynamic HTML label for column fields
        graph.getLabel = function(cell)
        {
            if (this.isHtmlLabel(cell))
            {
                var label = '';

                if (cell.value.primaryKey)
                {
                    label += '<img title="Primary Key" src="images/key.png" width="16" height="16" align="top">&nbsp;';
                }
                else
                {
                    label += '<img src="images/spacer.gif" width="16" height="1">&nbsp;';
                }

                if (cell.value.autoIncrement)
                {
                    label += '<img title="Auto Increment" src="images/plus.png" width="16" height="16" align="top">&nbsp;';
                }
                else if (cell.value.unique)
                {
                    label += '<img title="Unique" src="images/check.png" width="16" height="16" align="top">&nbsp;';
                }
                else
                {
                    label += '<img src="images/spacer.gif" width="16" height="1">&nbsp;';
                }

                return label + mxUtils.htmlEntities(cell.value.name, false) + ': ' +
                        mxUtils.htmlEntities(cell.value.type, false);
            }

            return mxGraph.prototype.getLabel.apply(this, arguments); // "supercall"
        };

        // Removes the source vertex if edges are removed
        graph.addListener(mxEvent.REMOVE_CELLS, function(sender, evt)
        {
            var cells = evt.getProperty('cells');

            for (var i = 0; i < cells.length; i++)
            {
                var cell = cells[i];

                if (this.model.isEdge(cell))
                {
                    var terminal = this.model.getTerminal(cell, true);
                    var parent = this.model.getParent(terminal);
                    this.model.remove(terminal);
                }
            }
        });

        // Disables drag-and-drop into non-swimlanes.
        graph.isValidDropTarget = function(cell, cells, evt)
        {
            return this.isSwimlane(cell);
        };

        // Installs a popupmenu handler using local function (see below).
        graph.popupMenuHandler.factoryMethod = function(menu, cell, evt)
        {
            createPopupMenu(editor, graph, menu, cell, evt);
        };

        // Adds all required styles to the graph (see below)
        configureStylesheet(graph);

        // Adds sidebar icon for the table object
        var tableObject = new Table('TABLENAME');
        var table = new mxCell(tableObject, new mxGeometry(0, 0, 200, 28), 'table');

        table.setVertex(true);
        addSidebarIcon(graph, sidebar, 	table, 'images/icons48/table.png');

        // Adds sidebar icon for the column object
        var columnObject = new Column('COLUMNNAME');
        var column = new mxCell(columnObject, new mxGeometry(0, 0, 0, 26));

        column.setVertex(true);
        column.setConnectable(false);

        addSidebarIcon(graph, sidebar, 	column, 'images/icons48/column.png');

        // Adds primary key field into table
        var firstColumn = column.clone();

        firstColumn.value.name = 'TABLENAME_ID';
        firstColumn.value.type = 'INTEGER';
        firstColumn.value.primaryKey = true;
        firstColumn.value.autoIncrement = true;

        table.insert(firstColumn);

        // Adds child columns for new connections between tables
        graph.addEdge = function(edge, parent, source, target, index)
        {
            // Finds the primary key child of the target table
            var primaryKey = null;
            var childCount = this.model.getChildCount(target);

            for (var i=0; i < childCount; i++)
            {
                var child = this.model.getChildAt(target, i);

                if (child.value.primaryKey)
                {
                    primaryKey = child;
                    break;
                }
            }

            if (primaryKey == null)
            {
                mxUtils.alert('Target table must have a primary key');
                return;
            }

            this.model.beginUpdate();
            try
            {
                var col1 = this.model.cloneCell(column);
                col1.value.name = primaryKey.value.name;
                col1.value.type = primaryKey.value.type;

                this.addCell(col1, source);
                source = col1;
                target = primaryKey;

                return mxGraph.prototype.addEdge.apply(this, arguments); // "supercall"
            }
            finally
            {
                this.model.endUpdate();
            }

            return null;
        };

        // Displays useful hints in a small semi-transparent box.
        var hints = document.createElement('div');
        hints.style.position = 'absolute';
        hints.style.overflow = 'hidden';
        hints.style.width = '230px';
        hints.style.bottom = '56px';
        hints.style.height = '86px';
        hints.style.right = '20px';

        hints.style.background = 'black';
        hints.style.color = 'white';
        hints.style.fontFamily = 'Arial';
        hints.style.fontSize = '10px';
        hints.style.padding = '4px';

        mxUtils.setOpacity(hints, 50);

        mxUtils.writeln(hints, '- Drag an image from the sidebar to the graph');
        mxUtils.writeln(hints, '- Doubleclick on a table or column to edit');
        mxUtils.writeln(hints, '- Shift- or Rightclick and drag for panning');
        mxUtils.writeln(hints, '- Move the mouse over a cell to see a tooltip');
        mxUtils.writeln(hints, '- Click and drag a table to move and connect');
        mxUtils.writeln(hints, '- Shift- or Rightclick to show a popup menu');
        document.body.appendChild(hints);

        // Creates a new DIV that is used as a toolbar and adds
        // toolbar buttons.
        var spacer = document.createElement('div');
        spacer.style.display = 'inline';
        spacer.style.padding = '8px';

        addToolbarButton(editor, toolbar, 'properties', 'Properties', 'editors/images/properties.gif');

        // Defines a new export action
        editor.addAction('properties', function(editor, cell)
        {
            if (cell == null)
            {
                cell = graph.getSelectionCell();
            }

            if (graph.isHtmlLabel(cell))
            {
                showProperties(graph, cell);
            }
        });

        addToolbarButton(editor, toolbar, 'delete', 'Delete', 'images/delete2.png');

        toolbar.appendChild(spacer.cloneNode(true));

        addToolbarButton(editor, toolbar, 'undo', '', 'images/undo.png');
        addToolbarButton(editor, toolbar, 'redo', '', 'images/redo.png');

        toolbar.appendChild(spacer.cloneNode(true));

        addToolbarButton(editor, toolbar, 'show', 'Show', 'images/camera.png');
        addToolbarButton(editor, toolbar, 'print', 'Print', 'images/printer.png');

        toolbar.appendChild(spacer.cloneNode(true));

        // Defines a create SQK action
        editor.addAction('showSql', function(editor, cell)
        {
            var sql = createSql(graph);

            if (sql.length > 0)
            {
                var textarea = document.createElement('textarea');
                textarea.style.width = '400px';
                textarea.style.height = '400px';

                textarea.value = sql;
                showModalWindow('SQL', textarea, 410, 440);
            }
            else
            {
                mxUtils.alert('Schema is empty');
            }
        });

        // Defines a new export action
        editor.addAction('createGears', function(editor, cell)
        {
            var sql = createSql(graph);

            if (sql.length > 0)
            {
                loadGoogleGears();

                try
                {
                    var db = google.gears.factory.create('beta.database', '1.0');
                    var name = mxUtils.prompt('Enter name of new database', 'MyDatabase');

                    if (name != null)
                    {
                        db.open(name);

                        // Checks if database is empty
                        var rs = db.execute('SELECT * FROM sqlite_master');

                        if (rs.isValidRow())
                        {
                            if (mxUtils.confirm(name+' exists. Do you want to continue? This will replace existing tables.') == 0)
                            {
                                return;
                            }
                        }

                        try
                        {
                            db.execute(sql);
                            mxUtils.alert(name+' successfully created');
                        }
                        catch (e)
                        {
                            mxUtils.alert('SQL Error: '+e.message);
                        }
                    }
                }
                catch (e)
                {
                    mxUtils.alert('Google Gears is not available: '+e.message);
                }
            }
            else
            {
                mxUtils.alert('Schema is empty');
            }
        });

        addToolbarButton(editor, toolbar, 'showSql', 'Show SQL', 'images/export1.png');
        addToolbarButton(editor, toolbar, 'createGears', 'Create in Google Gears', 'images/export1.png');

        toolbar.appendChild(spacer.cloneNode(true));

        // Defines export XML action
        editor.addAction('export', function(editor, cell)
        {
            var textarea = document.createElement('textarea');
            textarea.style.width = '400px';
            textarea.style.height = '400px';
            var enc = new mxCodec(mxUtils.createXmlDocument());
            var node = enc.encode(editor.graph.getModel());
            textarea.value = mxUtils.getPrettyXml(node);
            showModalWindow('XML', textarea, 410, 440,graph);
        });
        editor.addAction('setXMl', function(editor, cell)
        {
            var textarea = document.createElement('textarea');
            textarea.style.width = '400px';
            textarea.style.height = '400px';
            var enc = new mxCodec(mxUtils.createXmlDocument());
            var node = enc.encode(editor.graph.getModel());
            textarea.value = mxUtils.getPrettyXml(node);
            showModalWindow('XML', textarea, 410, 440);
        });


        addToolbarButton(editor, toolbar, 'export', 'Export XML', 'images/export1.png');

        // Adds toolbar buttons into the status bar at the bottom
        // of the window.
        addToolbarButton(editor, status, 'collapseAll', 'Collapse All', 'images/navigate_minus.png', true);
        addToolbarButton(editor, status, 'expandAll', 'Expand All', 'images/navigate_plus.png', true);

        status.appendChild(spacer.cloneNode(true));

        addToolbarButton(editor, status, 'zoomIn', '', 'images/zoom_in.png', true);
        addToolbarButton(editor, status, 'zoomOut', '', 'images/zoom_out.png', true);
        addToolbarButton(editor, status, 'actualSize', '', 'images/view_1_1.png', true);
        addToolbarButton(editor, status, 'fit', '', 'images/fit_to_size.png', true);

        // Creates the outline (navigator, overview) for moving
        // around the graph in the top, right corner of the window.
        var outln = new mxOutline(graph, outline);

        // Fades-out the splash screen after the UI has been loaded.
        var splash = document.getElementById('splash');
        if (splash != null)
        {
            try
            {
                mxEvent.release(splash);
                mxEffects.fadeOut(splash, 100, true);
            }
            catch (e)
            {

                // mxUtils is not available (library not loaded)
                splash.parentNode.removeChild(splash);
            }
        }
    }
}

function addToolbarButton(editor, toolbar, action, label, image, isTransparent)
{
    var button = document.createElement('button');
    button.style.fontSize = '10';
    if (image != null)
    {
        var img = document.createElement('img');
        img.setAttribute('src', image);
        img.style.width = '16px';
        img.style.height = '16px';
        img.style.verticalAlign = 'middle';
        img.style.marginRight = '2px';
        button.appendChild(img);
    }
    if (isTransparent)
    {
        button.style.background = 'transparent';
        button.style.color = '#FFFFFF';
        button.style.border = 'none';
    }
    mxEvent.addListener(button, 'click', function(evt)
    {
        editor.execute(action);
    });
    mxUtils.write(button, label);
    toolbar.appendChild(button);
};

function showModalWindow(title, content, width, height,graph)
{
    var background = document.createElement('div');
    background.style.position = 'absolute';
    background.style.left = '0px';
    background.style.top = '0px';
    background.style.right = '0px';
    background.style.bottom = '0px';
    background.style.background = 'black';
    mxUtils.setOpacity(background, 50);
    document.body.appendChild(background);

    if (mxClient.IS_QUIRKS)
    {
        new mxDivResizer(background);
    }

    var x = Math.max(0, document.body.scrollWidth/2-width/2);
    var y = Math.max(10, (document.body.scrollHeight ||
            document.documentElement.scrollHeight)/2-height*2/3);
    var wnd = new mxWindow(title, content, x, y, width, height, true, true);
    wnd.setClosable(true);

    wnd.addListener(mxEvent.CLOSE,function(wnd){
        var value = wnd.content.value;
        var req = mxUtils.parseXml(value);
        var root = req.documentElement;
        var dec = new mxCodec(root);
        graph.getModel().beginUpdate();
        dec.decode(root, graph.getModel());
//				configureStylesheet(graph);
        graph.getModel().endUpdate();

    })
    // Fades the background out after after the window has been closed
    wnd.addListener(mxEvent.DESTROY, function(evt)
    {
        mxEffects.fadeOut(background, 50, true,
                10, 30, true);
    });

    wnd.setVisible(true);

    return wnd;
};

function addSidebarIcon(graph, sidebar, prototype, image)
{
    // Function that is executed when the image is dropped on
    // the graph. The cell argument points to the cell under
    // the mousepointer if there is one.
    var funct = function(graph, evt, cell)
    {
        graph.stopEditing(false);

        var pt = graph.getPointForEvent(evt);

        var parent = graph.getDefaultParent();
        var model = graph.getModel();

        var isTable = graph.isSwimlane(prototype);
        var name = null;

        if (!isTable)
        {
            parent = cell;
            var pstate = graph.getView().getState(parent);

            if (parent == null || pstate == null)
            {
                mxUtils.alert('Drop target must be a table');
                return;
            }

            pt.x -= pstate.x;
            pt.y -= pstate.y;

            var columnCount = graph.model.getChildCount(parent)+1;
            name = mxUtils.prompt('Enter name for new column', 'COLUMN'+columnCount);
        }
        else
        {
            var tableCount = 0;
            var childCount = graph.model.getChildCount(parent);

            for (var i=0; i<childCount; i++)
            {
                if (!graph.model.isEdge(graph.model.getChildAt(parent, i)))
                {
                    tableCount++;
                }
            }

            var name = mxUtils.prompt('Enter name for new table', 'TABLE'+(tableCount+1));
        }

        if (name != null)
        {
            var v1 = model.cloneCell(prototype);

            model.beginUpdate();
            try
            {
                v1.value.name = name;
                v1.geometry.x = pt.x;
                v1.geometry.y = pt.y;

                graph.addCell(v1, parent);

                if (isTable)
                {
                    v1.geometry.alternateBounds = new mxRectangle(0, 0, v1.geometry.width, v1.geometry.height);
                    v1.children[0].value.name = name + '_ID';
                }
            }
            finally
            {
                model.endUpdate();
            }

            graph.setSelectionCell(v1);
        }
    }

    // Creates the image which is used as the sidebar icon (drag source)
    var img = document.createElement('img');
    img.setAttribute('src', image);
    img.style.width = '48px';
    img.style.height = '48px';
    img.title = 'Drag this to the diagram to create a new vertex';
    sidebar.appendChild(img);

    // Creates the image which is used as the drag icon (preview)
    var dragImage = img.cloneNode(true);
    var ds = mxUtils.makeDraggable(img, graph, funct, dragImage);

    // Adds highlight of target tables for columns
    ds.highlightDropTargets = true;
    ds.getDropTarget = function(graph, x, y)
    {
        if (graph.isSwimlane(prototype))
        {
            return null;
        }
        else
        {
            var cell = graph.getCellAt(x, y);

            if (graph.isSwimlane(cell))
            {
                return cell;
            }
            else
            {
                var parent = graph.getModel().getParent(cell);

                if (graph.isSwimlane(parent))
                {
                    return parent;
                }
            }
        }
    };
};

function configureStylesheet(graph)
{
    var style = new Object();
    style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_RECTANGLE;
    style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
    style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_LEFT;
    style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_MIDDLE;
    style[mxConstants.STYLE_FONTCOLOR] = '#000000';
    style[mxConstants.STYLE_FONTSIZE] = '11';
    style[mxConstants.STYLE_FONTSTYLE] = 0;
    style[mxConstants.STYLE_SPACING_LEFT] = '4';
    style[mxConstants.STYLE_IMAGE_WIDTH] = '48';
    style[mxConstants.STYLE_IMAGE_HEIGHT] = '48';
    graph.getStylesheet().putDefaultVertexStyle(style);

    style = new Object();
    style[mxConstants.STYLE_SHAPE] = mxConstants.SHAPE_SWIMLANE;
    style[mxConstants.STYLE_PERIMETER] = mxPerimeter.RectanglePerimeter;
    style[mxConstants.STYLE_ALIGN] = mxConstants.ALIGN_CENTER;
    style[mxConstants.STYLE_VERTICAL_ALIGN] = mxConstants.ALIGN_TOP;
    style[mxConstants.STYLE_GRADIENTCOLOR] = '#41B9F5';
    style[mxConstants.STYLE_FILLCOLOR] = '#8CCDF5';
    style[mxConstants.STYLE_SWIMLANE_FILLCOLOR] = '#ffffff';
    style[mxConstants.STYLE_STROKECOLOR] = '#1B78C8';
    style[mxConstants.STYLE_FONTCOLOR] = '#000000';
    style[mxConstants.STYLE_STROKEWIDTH] = '2';
    style[mxConstants.STYLE_STARTSIZE] = '28';
    style[mxConstants.STYLE_VERTICAL_ALIGN] = 'middle';
    style[mxConstants.STYLE_FONTSIZE] = '12';
    style[mxConstants.STYLE_FONTSTYLE] = 1;
    style[mxConstants.STYLE_IMAGE] = 'images/icons48/table.png';
    // Looks better without opacity if shadow is enabled
    //style[mxConstants.STYLE_OPACITY] = '80';
    style[mxConstants.STYLE_SHADOW] = 1;
    graph.getStylesheet().putCellStyle('table', style);

    style = graph.stylesheet.getDefaultEdgeStyle();
    style[mxConstants.STYLE_LABEL_BACKGROUNDCOLOR] = '#FFFFFF';
    style[mxConstants.STYLE_STROKEWIDTH] = '2';
    style[mxConstants.STYLE_ROUNDED] = true;
    style[mxConstants.STYLE_EDGE] = mxEdgeStyle.EntityRelation;
};

// Function to create the entries in the popupmenu
function createPopupMenu(editor, graph, menu, cell, evt)
{
    if (cell != null)
    {
        if (graph.isHtmlLabel(cell))
        {
            menu.addItem('Properties', 'editors/images/properties.gif', function()
            {
                editor.execute('properties', cell);
            });

            menu.addSeparator();
        }

        menu.addItem('Delete', 'images/delete2.png', function()
        {
            editor.execute('delete', cell);
        });

        menu.addSeparator();
    }

    menu.addItem('Undo', 'images/undo.png', function()
    {
        editor.execute('undo', cell);
    });

    menu.addItem('Redo', 'images/redo.png', function()
    {
        editor.execute('redo', cell);
    });

    menu.addSeparator();


    menu.addItem('Show SQL', 'images/export1.png', function()
    {
        editor.execute('showSql', cell);
    });
};

function showProperties(graph, cell)
{
    // Creates a form for the user object inside
    // the cell
    var form = new mxForm('properties');

    // Adds a field for the columnname
    var nameField = form.addText('Name', cell.value.name);
    var typeField = form.addText('Type', cell.value.type);

    var primaryKeyField = form.addCheckbox('Primary Key', cell.value.primaryKey);
    var autoIncrementField = form.addCheckbox('Auto Increment', cell.value.autoIncrement);
    var notNullField = form.addCheckbox('Not Null', cell.value.notNull);
    var uniqueField = form.addCheckbox('Unique', cell.value.unique);

    var defaultField = form.addText('Default', cell.value.defaultValue || '');
    var useDefaultField = form.addCheckbox('Use Default', (cell.value.defaultValue != null));

    var wnd = null;

    // Defines the function to be executed when the
    // OK button is pressed in the dialog
    var okFunction = function()
    {
        var clone = cell.value.clone();

        clone.name = nameField.value;
        clone.type = typeField.value;

        if (useDefaultField.checked)
        {
            clone.defaultValue = defaultField.value;
        }
        else
        {
            clone.defaultValue = null;
        }

        clone.primaryKey = primaryKeyField.checked;
        clone.autoIncrement = autoIncrementField.checked;
        clone.notNull = notNullField.checked;
        clone.unique = uniqueField.checked;

        graph.model.setValue(cell, clone);

        wnd.destroy();
    }

    // Defines the function to be executed when the
    // Cancel button is pressed in the dialog
    var cancelFunction = function()
    {
        wnd.destroy();
    }
    form.addButtons(okFunction, cancelFunction);

    var parent = graph.model.getParent(cell);
    var name = parent.value.name + '.' + cell.value.name;
    wnd = showModalWindow(name, form.table, 240, 240,graph);
};

function createSql(graph)
{
    var sql = [];
    var parent = graph.getDefaultParent();
    var childCount = graph.model.getChildCount(parent);

    for (var i=0; i<childCount; i++)
    {
        var child = graph.model.getChildAt(parent, i);

        if (!graph.model.isEdge(child))
        {
            sql.push('CREATE TABLE IF NOT EXISTS '+child.value.name+' (');

            var columnCount = graph.model.getChildCount(child);

            if (columnCount > 0)
            {
                for (var j=0; j<columnCount; j++)
                {
                    var column = graph.model.getChildAt(child, j).value;

                    sql.push('\n    '+column.name+' '+column.type);

                    if (column.notNull)
                    {
                        sql.push(' NOT NULL');
                    }

                    if (column.primaryKey)
                    {
                        sql.push(' PRIMARY KEY');
                    }

                    if (column.autoIncrement)
                    {
                        sql.push(' AUTOINCREMENT');
                    }

                    if (column.unique)
                    {
                        sql.push(' UNIQUE');
                    }

                    if (column.defaultValue != null)
                    {
                        sql.push(' DEFAULT '+column.defaultValue);
                    }

                    sql.push(',');
                }

                sql.splice(sql.length-1, 1);
                sql.push('\n);');
            }

            sql.push('\n');
        }
    }

    return sql.join('');
};

function loadGoogleGears()
{
    // We are already defined. Hooray!
    if (window.google && google.gears) {
        return;
    }

    var factory = null;

    // Firefox
    if (typeof GearsFactory != 'undefined') {
        factory = new GearsFactory();
    } else {
        // IE
        try {
            factory = new ActiveXObject('Gears.Factory');
        } catch (e) {
            // Safari
            if (navigator.mimeTypes["application/x-googlegears"]) {
                factory = document.createElement("object");
                factory.style.display = "none";
                factory.width = 0;
                factory.height = 0;
                factory.type = "application/x-googlegears";
                document.documentElement.appendChild(factory);
            }
        }
    }

    // *Do not* define any objects if Gears is not installed. This mimics the
    // behavior of Gears defining the objects in the future.
    if (!factory) {
        return;
    }

    // Now set up the objects, being careful not to overwrite anything.
    if (!window.google) {
        window.google = {};
    }

    if (!google.gears) {
        google.gears = {factory: factory};
    }
};

// Defines the column user object
function Column(name)
{
    this.name = name;
};

Column.prototype.type = 'TEXT';

Column.prototype.defaultValue = null;

Column.prototype.primaryKey = false;

Column.prototype.autoIncrement = false;

Column.prototype.notNull = false;

Column.prototype.unique = false;

Column.prototype.clone = function()
{
    return mxUtils.clone(this);
};

// Defines the table user object
function Table(name)
{
    this.name = name;
};

Table.prototype.clone = function()
{
    return mxUtils.clone(this);
};
//startArrow=diamond;startFill=1;startSize=10;endArrow=diamond;endFill=0;endSize=10;html=1;strokeColor=#171FFF;
</script>
</head>

<!-- Page passes the container for the graph to the program -->
<body onload="main(document.getElementById('graphContainer'),
			document.getElementById('outlineContainer'),
		 	document.getElementById('toolbarContainer'),
			document.getElementById('sidebarContainer'),
			document.getElementById('statusContainer'));">

<!-- Creates a container for the splash screen -->
<div id="splash"
     style="position:absolute;top:0px;left:0px;width:100%;height:100%;background:white;z-index:1;">
    <center id="splash" style="padding-top:230px;">
        <img src="editors/images/loading.gif">
    </center>
</div>

<!-- Creates a container for the sidebar -->
<div id="toolbarContainer"
     style="position:absolute;white-space:nowrap;overflow:hidden;top:0px;left:0px;max-height:24px;height:36px;right:0px;padding:6px;background-image:url('images/toolbar_bg.gif');">
</div>

<!-- Creates a container for the toolboox -->
<div id="sidebarContainer"
     style="position:absolute;overflow:hidden;top:36px;left:0px;bottom:36px;max-width:52px;width:56px;padding-top:10px;padding-left:4px;background-image:url('images/sidebar_bg.gif');">
</div>

<!-- Creates a container for the graph -->
<div id="graphContainer"
     style="position:absolute;overflow:hidden;top:36px;left:60px;bottom:36px;right:0px;">
</div>

<!-- Creates a container for the outline -->
<div id="outlineContainer"
     style="position:absolute;overflow:hidden;top:36px;right:0px;width:200px;height:140px;background:transparent;border-style:solid;border-color:black;">
</div>

<!-- Creates a container for the sidebar -->
<div id="statusContainer"
     style="text-align:right;position:absolute;overflow:hidden;bottom:0px;left:0px;max-height:24px;height:36px;right:0px;color:white;padding:6px;background-image:url('images/toolbar_bg.gif');">
    <div style="font-size:10pt;float:left;">
        Created with <a href="http://www.jgraph.com" target="_blank">mxGraph</a>
    </div>
</div>
</body>
</html>
